/*
 * ConsoleInterface.cpp
 *
 *  Created on: 2021年8月29日
 *      Author: vicent-PC
 */

#include "ConsoleService.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "OledTestCase.h"
#include "argtable3/argtable3.h"
#include "c3log.h"
#include "cmd_system.h"
#include "driver/i2c.h"
#include "esp_console.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "sdkconfig.h"

#include "hal/motor/CommMotorManager.h"
#include "hal/motor/MotorManager.h"
#include "hal/motor/SteeringMotorManager.h"
#include "screen_hal/DisplayCanvas.h"

ConsoleService::ConsoleService() {
    mContext = nullptr;
}

ConsoleService::~ConsoleService() {
}

static int do_cmd(int argc, char **argv) {
    printf("recieved help!");
    return 0;
}

static struct {
    struct arg_int *chip_address;
    struct arg_int *size;
    struct arg_end *end;
} con_cmd_args;

void register_cmdtools(void) {
    con_cmd_args.chip_address =
        arg_int1("c", "chip", "<chip_addr>",
                 "Specify the address of the chip on that bus");
    con_cmd_args.size =
        arg_int0("s", "size", "<size>", "Specify the size of each read");
    con_cmd_args.end = arg_end(1);
    const esp_console_cmd_t con_cmd = {.command = "cmd",
                                       .help = "Exe cmd",
                                       .hint = NULL,
                                       .func = &do_cmd,
                                       .argtable = &con_cmd_args};
    ESP_ERROR_CHECK(esp_console_cmd_register(&con_cmd));
}

void ConsoleService::init() {
    esp_console_repl_t *repl = NULL;
    esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();

    // repl_config.history_save_path = HISTORY_PATH;
    // repl_config.prompt = "i2c-tools>";

    esp_console_dev_uart_config_t uart_config =
        ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(
        esp_console_new_repl_uart(&uart_config, &repl_config, &repl));

    register_cmdtools();
    register_system();
    // start console REPL
    ESP_ERROR_CHECK(esp_console_start_repl(repl));
}

uint8_t *oled_parse(const char *bmp_code, size_t &size) {
    LOGI("%s E", __func__);
    // bmp format is: 0xff 0xff
    size = strlen(bmp_code) / 5;
    uint8_t *bmp = (uint8_t *)malloc(size);
    char *stop;
    for (int i = 0; i < size; i++) {
        bmp[i] = (uint8_t)strtol(bmp_code + i * 5, &stop, 16);  // 16进制
    }
    for (int i = 0; i < size; i++) {
        LOGI("bmp i:%d 0x%x", i, bmp[i]);
    }
    LOGI("%s X", __func__);
    return bmp;
}

void ConsoleService::processCmd(const char *cmd) {
    LOGI("%s E", __func__);
    if (nullptr != cmd) {
        LOGI("rec cmd: %s", cmd);
    } else {
        return;
    }
    char *str_loc = nullptr;

    if ((str_loc = strstr(cmd, "oled")) != nullptr) {
        LOGI("content:%s", str_loc + strlen("oled"));
        size_t size = 0;
        uint8_t *bmp = oled_parse(str_loc + strlen("oled"), size);

        // display
        if (nullptr != mContext) {
            OledTestCase *context = (OledTestCase *)mContext;
            if (32 == size) {
                context->drawBmp(0, 0, 16, 16, (uint16_t *)bmp);
            } else if (1024 == size) {
                context->drawBmp(0, 0, 128, 64, (uint16_t *)bmp);
            }
            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }

        if (bmp != nullptr) {
            free(bmp);
        }
    } else if ((str_loc = strstr(cmd, "motor")) != nullptr) {
        char *cmd_params = str_loc + strlen("motor");
        int step = atoi(cmd_params);
        LOGI("cmd_params:%s parsed step:%d", cmd_params, step);
        MotorManager motorMgr;
        motorMgr.stepRun(abs(step), (step > 0));
    } else if ((str_loc = strstr(cmd, "restart")) != nullptr) {
        LOGI("CMD restarting...");
        esp_restart();
    } else if ((str_loc = strstr(cmd, "steer")) != nullptr) {
        char *cmd_params = str_loc + strlen("steer");
        int step = atoi(cmd_params);
        LOGI("cmd_params:%s parsed step:%d", cmd_params, step);
        SteeringMotorManager motorMgr;
        motorMgr.stepRun(abs(step), (step > 0));
    } else if ((str_loc = strstr(cmd, "solenoid")) != nullptr) {
        char *cmd_params = str_loc + strlen("solenoid");
        int step = atoi(cmd_params);
        LOGI("cmd_params:%s parsed step:%d", cmd_params, step);
        CommMotorManager motorMgr;
        motorMgr.stepRun(1);
        motorMgr.stepRun(0);
    } else if ((str_loc = strstr(cmd, "dumplog")) != nullptr) {
        LOGI("dump_log start...");
        dump_log();
    } else if ((str_loc = strstr(cmd, "display")) != nullptr) {     // display: y_num string
        char *cmd_params = str_loc + strlen("display ");
        LOGI("display:", cmd_params);
        int y = atoi(cmd_params);
        OLEDDisplay* tempPen = DisplayCanvas::getInstance()->getPen();
        tempPen->clear();
        tempPen->drawString(1, y, cmd_params);   // strength
        tempPen->display();
        
    }
    LOGI("%s X", __func__);
}

void ConsoleService::setContext(void *context) { mContext = context; }